Skip to content

ci: skip-existing on PyPI publish to unblock concurrent PR pushes#96

Merged
OhYee merged 1 commit intomainfrom
fix/ci-skip-existing-publish
May 7, 2026
Merged

ci: skip-existing on PyPI publish to unblock concurrent PR pushes#96
OhYee merged 1 commit intomainfrom
fix/ci-skip-existing-publish

Conversation

@OhYee
Copy link
Copy Markdown
Member

@OhYee OhYee commented May 7, 2026

问题

PR #88 的 CI 失败暴露了 `ci.yml` 中一个发布流水线缺陷:

```
ERROR: HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/
File already exists ('agentrun_inner_test-0.0.187-py3-none-any.whl', ...)
```

测试、类型检查、构建、验证全部通过,仅 `Publish to PyPI` 步骤报错,但整个 CI 标红,导致 `mergeStateStatus=BLOCKED`,阻塞 PR 合入。

根因

`.github/workflows/ci.yml` L77-92 的版本计算逻辑:每次 push 都从 PyPI API 拉取 `agentrun-inner-test` 最新版本,自增 patch 号作为下一版。

当一个 PR 多次 push commit,或两个 CI run 因 PyPI API 缓存窗口拿到同样的"最新版本",会算出同一个下一版本(如两次都算到 `0.0.187`)。第二次 `Publish to PyPI` 自然 `400 File already exists`。

修复

为 `pypa/gh-action-pypi-publish` 加 `skip-existing: true`:遇到已存在版本时跳过并记录 warning,而非以 400 退出。

```yaml

  • name: Publish to PyPI
    if: steps.changes.outputs.agentrun_changed == 'true'
    uses: pypa/gh-action-pypi-publish@release/v1
    with:
    password: ${{ secrets.PYPI_API_TOKEN }}
    verify-metadata: false
  • skip-existing: true
    ```

参见 pypa/gh-action-pypi-publish 文档,该参数对应 twine 的 `--skip-existing`。

设计取舍

方案 评估
`skip-existing: true`(本 PR 选择) ✅ 1 行改动,不破坏现有"PR push 自动发 dev 包"语义
PR 上不发包,仅 main push 才发 ❌ 破坏现有内部消费方依赖(`pip install agentrun-inner-test==<dev_version>`)
用 commit SHA 做版本号 ❌ 改动大,影响内部消费方版本号格式

已知限制(不在本 PR 范围)

`skip-existing` 后存在隐性问题:PR 多次 push 时,第二次 push 的代码不会被发到 PyPI(版本号没变,跳过),消费方拿到的还是第一次的代码。

属于版本号自增逻辑的根本缺陷,但不阻塞当前修复。后续可在版本号中嵌入 commit SHA 实现唯一化(如 `0.0.187+sha.` 或 PEP 440 兼容的 `0.0.187.dev<run_number>`)。

为什么 release-test.yml 保持不动?

`release-test.yml` 是手动触发的工作流(`workflow_dispatch` + `workflow_call`),用户主动选择版本递增类型。在那里版本冲突应硬性报错让用户察觉,而非静默跳过。

测试计划

  • 合入后观察下次 PR 推送时 CI 行为:版本冲突应仅产生 warning,CI 整体应绿
  • PyPI 上 `agentrun-inner-test` 的版本应继续自增(仅在版本未冲突时)

合入这个 PR 后,未来 #77 等 PR 的 CI 不会再因发布步骤的版本号竞态而被阻塞。

Copilot AI review requested due to automatic review settings May 7, 2026 08:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the CI publish workflow to avoid failing the entire run when a computed “next version” already exists on PyPI (a race that can happen with concurrent runs or repeated pushes).

Changes:

  • Configure pypa/gh-action-pypi-publish with skip-existing: true so existing artifacts don’t hard-fail the job.
  • Add inline comments documenting why version collisions occur and why skipping is acceptable as a short-term fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/ci.yml
Comment on lines +166 to +169
# 当 PR 多次 push 或并发 CI 跑出相同版本号时,跳过已存在版本而非报错。
# 根因是版本号自增逻辑依赖 PyPI API 拉取最新版本,存在缓存/并发窗口。
# 不阻塞 PR 合入即可,长期方案是在版本号中嵌入 commit SHA 实现唯一化。
skip-existing: true
When a PR is pushed multiple times in quick succession (or two CI runs
race), the version-bump step can compute the same next version twice
because PyPI's JSON API has a small cache window after a release.
The second 'Publish to PyPI' then fails with HTTP 400 "File already
exists", marking the entire CI run red and blocking PR merge even
though tests, type-check, build and verify all passed.

Add skip-existing: true so the publish action treats an existing
version as a non-error (it logs a warning and exits 0). PR merge is
no longer gated by this race.

Side note: skip-existing means the second push's *content* won't be
republished under the same version. The proper long-term fix is to
embed the commit SHA in the dev version (e.g. 0.0.187+sha.<short>)
so each push gets a unique artefact. Tracked separately.

release-test.yml is intentionally left unchanged: it is triggered
manually with an explicit version bump, where a conflict should
fail loudly rather than be silently skipped.

Change-Id: I4be2fb05fd06e32b83dd64d52bd62bfe8b8355cf
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: OhYee <oyohyee@oyohyee.com>
@OhYee OhYee force-pushed the fix/ci-skip-existing-publish branch from 3f9a02b to 7ec9682 Compare May 7, 2026 08:10
@OhYee OhYee merged commit 1afdbf9 into main May 7, 2026
2 checks passed
@OhYee OhYee deleted the fix/ci-skip-existing-publish branch May 7, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants